home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / sockuser.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-15  |  13.9 KB  |  663 lines

  1. /* Higher level user subroutines built on top of the socket primitives
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Mods by PA0GRI
  5.  */
  6. #include "global.h"
  7. #include "config.h"
  8. #ifdef    ANSIPROTO
  9. #include <stdarg.h>
  10. #endif
  11. #include "mbuf.h"
  12. #include "proc.h"
  13. #include "socket.h"
  14. #ifdef    LZW
  15. #include "lzw.h"
  16. #endif
  17. #include "usock.h"
  18. #include "session.h"
  19. #include "nr4.h"
  20.  
  21. /*
  22. #define oldusputs
  23. */
  24.  
  25. extern void backEmUp __ARGS((int len));
  26.  
  27.  
  28. /* Higher-level receive routine, intended for connection-oriented sockets.
  29.  * Can be used with datagram sockets, although the sender id is lost.
  30.  */
  31. int
  32. recv(s,buf,len,flags)
  33. int s;        /* Socket index */
  34. char *buf;    /* User buffer */
  35. int len;    /* Max length to receive */
  36. int flags;    /* Unused; will eventually select oob data, etc */
  37. {
  38.     struct mbuf *bp;
  39.     int cnt;
  40.  
  41.     if(len == 0)
  42.         return 0;    /* Otherwise would be interp as "all" */
  43.  
  44.     cnt = recv_mbuf(s,&bp,flags,NULLCHAR,(int *)NULL);
  45.     if(cnt > 0){
  46.         cnt = min(cnt,len);
  47.         pullup(&bp,buf,(int16)cnt);
  48.         free_p(bp);
  49.     }
  50.     return cnt;
  51. }
  52. /* Higher level receive routine, intended for datagram sockets. Can also
  53.  * be used for connection-oriented sockets, although from and fromlen are
  54.  * ignored.
  55.  */
  56. int
  57. recvfrom(s,buf,len,flags,from,fromlen)
  58. int s;        /* Socket index */
  59. char *buf;    /* User buffer */
  60. int len;    /* Maximum length */
  61. int flags;    /* Unused; will eventually select oob data, etc */
  62. char *from;    /* Source address, only for datagrams */
  63. int *fromlen;    /* Length of source address */
  64. {
  65.     struct mbuf *bp;
  66.     register int cnt;
  67.  
  68.     cnt = recv_mbuf(s,&bp,flags,from,fromlen);
  69.     if(cnt > 0){
  70.         cnt = min(cnt,len);
  71.         pullup(&bp,buf,(int16)cnt);
  72.         free_p(bp);
  73.     }
  74.     return cnt;
  75. }
  76. /* High level send routine */
  77. int
  78. send(s,buf,len,flags)
  79. int s;        /* Socket index */
  80. char *buf;    /* User buffer */
  81. int len;    /* Length of buffer */
  82. int flags;    /* Unused; will eventually select oob data, etc */
  83. {
  84.     register struct mbuf *bp;
  85.     char sock[MAXSOCKSIZE];
  86.     int i = MAXSOCKSIZE;
  87.  
  88.     if(getpeername(s,sock,&i) == -1)
  89.         return -1;
  90.     bp = qdata(buf,(int16)len);
  91.     return send_mbuf(s,bp,flags,sock,i);
  92. }
  93. /* High level send routine, intended for datagram sockets. Can be used on
  94.  * connection-oriented sockets, but "to" and "tolen" are ignored.
  95.  */
  96. int
  97. sendto(s,buf,len,flags,to,tolen)
  98. int s;        /* Socket index */
  99. char *buf;    /* User buffer */
  100. int len;    /* Length of buffer */
  101. int flags;    /* Unused; will eventually select oob data, etc */
  102. char *to;    /* Destination, only for datagrams */
  103. int tolen;    /* Length of destination */
  104. {
  105.     register struct mbuf *bp;
  106.  
  107.     bp = qdata(buf,(int16)len);
  108.     return send_mbuf(s,bp,flags,to,tolen);
  109. }
  110. /* Receive a newline-terminated line from a socket, returning # chars read.
  111.  * The end-of-line sequence is recognized and translated into a single '\n'.
  112.  */
  113. int
  114. recvline(s,buf,len)
  115. int s;        /* Socket index */
  116. unsigned char *buf;    /* User buffer */
  117. unsigned len;    /* Length of buffer */
  118. {
  119.     int c;
  120.     int cnt = 0;
  121.  
  122.     while(len-- > 1){
  123.         if((c = recvchar(s)) == EOF){
  124.             cnt = -1;
  125.             break;
  126.         }
  127.         if(buf != NULLCHAR)
  128.             *buf++ = c;
  129.         cnt++;
  130.         if(uchar(c) == '\n')
  131.             break;
  132.     }
  133.     if(buf != NULLCHAR)
  134.         *buf = '\0';
  135.     return cnt;
  136. }
  137. #if    defined(ANSIPROTO)
  138. /* Do printf on a user socket */
  139. int
  140. usprintf(int s,char *fmt,...)
  141. {
  142.     va_list args;
  143.     int len;
  144.  
  145.     va_start(args,fmt);
  146.     len = usvprintf(s,fmt,args);
  147.     va_end(args);
  148.     return len;
  149. }
  150. /* Printf on standard output socket */
  151. int
  152. tprintf(char *fmt,...)
  153. {
  154.     va_list args;
  155.     int len;
  156.  
  157.     va_start(args,fmt);
  158.     len = usvprintf(Curproc->output,fmt,args);
  159.     va_end(args);
  160.     return len;
  161. }
  162. /* The guts of printf, uses variable arg version of sprintf */
  163. int
  164. usvprintf(int s,char *fmt, va_list args)
  165. {
  166.     int len,withargs;
  167.     char *buf;
  168.  
  169.     if(strchr(fmt,'%') == NULLCHAR){
  170.         /* Common case optimization: no args, so we don't
  171.          * need vsprintf()
  172.          */
  173.         withargs = 0;
  174.         buf = fmt;
  175.         len = strlen(fmt);
  176.     } else {
  177.         /* Use a default value that is hopefully longer than the
  178.          * biggest output string we'll ever print (!)
  179.          */
  180.         withargs = 1;
  181.         buf = mallocw(SOBUF);
  182. /* Start of mod by N4YYH */
  183.         if((len=vsprintf(buf,fmt,args)) >= SOBUF) {
  184.             /* It's too late to be sorry. He's dead, Jim. */
  185. #ifdef STKTRACE
  186.             stktrace();
  187. #endif
  188.             log(s,"usvprintf() has exceeded the size of it's buffer. Restarting NOS.");
  189.             where_outta_here(1);
  190.         }
  191. /* End of mod by N4YYH */
  192. /*
  193.         len = strlen(buf);
  194. */
  195.     }
  196.     if(usputs(s,buf) == EOF)
  197.         len = -1;
  198.     if(withargs)
  199.         free(buf);
  200.     return len;
  201. }
  202. #else
  203. /*VARARGS*/
  204. /* Printf to standard output socket */
  205. int
  206. tprintf(fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
  207. char *fmt;        /* Message format */
  208. int arg1,arg2,arg3;    /* Arguments */
  209. int arg4,arg5,arg6;
  210. int arg7,arg8,arg9;
  211. int arg10,arg11,arg12;
  212. {
  213.     return usprintf(Curproc->output,fmt,arg1,arg2,arg3,arg4,arg5,arg6,
  214.         arg7,arg8,arg9,arg10,arg11,arg12);
  215. }
  216. /* Printf to socket. Doesn't use ANSI vsprintf */
  217. int
  218. usprintf(s,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
  219. int s;            /* Socket index */
  220. char *fmt;        /* Message format */
  221. int arg1,arg2,arg3;    /* Arguments */
  222. int arg4,arg5,arg6;
  223. int arg7,arg8,arg9;
  224. int arg10,arg11,arg12;
  225. {
  226.     int len,withargs;
  227.     char *buf;
  228.  
  229.     if(strchr(fmt,'%') == NULLCHAR){
  230.         /* No args, so we don't need vsprintf() */
  231.         withargs = 0;
  232.         buf = fmt;
  233.         len = strlen(fmt);
  234.     } else {
  235.         /* Use a default value that is hopefully longer than the
  236.          * biggest output string we'll ever print (!)
  237.          */
  238.         withargs = 1;
  239.         buf = mallocw(SOBUF);
  240. /* Start of mod by N4YYH */
  241.         if((len=sprintf(buf,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,
  242.            arg8,arg9,arg10,arg11,arg12)) >= SOBUF) {
  243.             /* It's too late to be sorry. He's dead, Jim. */
  244.             log(s,"usvprintf() has exceeded the size of it's buffer. Restarting NOS.");
  245.             where_outta_here(1);
  246.         }
  247. /* End of mod by N4YYH */
  248. /*        len = strlen(buf);    */
  249.     }
  250.     if(usputs(s,buf) == EOF)
  251.         len = -1;
  252.  
  253.     if(withargs)
  254.         free(buf);
  255.     return len;
  256. }
  257. #endif
  258. /* Buffered putchar to a socket */
  259. int
  260. usputc(s,c)
  261. int s;
  262. unsigned char c;
  263. {
  264.     struct usock *up;
  265.     register struct mbuf *bp;
  266.     unsigned char *cp;
  267.     int newline,len;
  268.  
  269.     if((up = itop(s)) == NULLUSOCK){
  270.         errno = EBADF;
  271.         return -1;
  272.     }
  273.     if(c == '\n' && (up->flag & SOCK_ASCII)){
  274.         newline = 1;
  275.         len = strlen(up->eol);
  276.     } else {
  277.         newline = 0;
  278.         len = 1;
  279.     }
  280. #ifndef LZW
  281.     /* Make sure there's room in the current buffer, if any */
  282.     if((bp = up->obuf) != NULLBUF){
  283.         if((bp->cnt >= bp->size - len) && usflush(s) == -1)
  284.             return EOF;
  285.     }
  286. #endif
  287.     if(up->obuf == NULLBUF){
  288.         /* Allocate a buffer of appropriate size */
  289. #ifdef notdef
  290.         /* since I now fragment nr4 packets in send_nr4(),
  291.          * don't worry, be happy :-) - WG7J
  292.          */
  293.         switch(up->type){
  294.         case TYPE_NETROML4:
  295.             up->obuf = ambufw(NR4MAXINFO);
  296.             break;
  297.         default:
  298.             up->obuf = ambufw(BUFSIZ);
  299.             break;
  300.         }
  301. #endif
  302.         up->obuf = ambufw(BUFSIZ);
  303.     }
  304.     /* Note: the buffer must be larger than the end-of-line sequence! */
  305.     bp = up->obuf;
  306.     cp = &bp->data[bp->cnt];
  307.     if(newline){
  308.         /* Translate into appropriate end-of-line sequence */
  309. #ifdef    LZW
  310.         for(cp = up->eol;*cp != '\0';cp++)
  311.             if(up->zout == NULLLZW)
  312.                 bp->data[bp->cnt++] = *cp;
  313.             else
  314.                 lzwencode(s,*cp);
  315. #else
  316.         strncpy(cp,up->eol,len);
  317. #endif
  318.     } else {
  319. #ifdef    LZW
  320.         if(up->zout == NULLLZW)
  321.             bp->data[bp->cnt++] = c;
  322.         else
  323.             lzwencode(s,c);
  324.     }
  325. #else
  326.         *cp = c;
  327.     }
  328.     bp->cnt += len;
  329. #endif
  330.     /* Flush if necessary and leave enough room for a coming eol */
  331.     if((c == up->flush && up->flush != -1) || bp->cnt >= bp->size-9)
  332.         if(usflush(s) == -1)
  333.             return -1;
  334.  
  335.     return (int)uchar(c);
  336. }
  337. /* Put a character to standard output socket */
  338. int
  339. tputc(c)
  340. unsigned char c;
  341. {
  342.     return usputc(Curproc->output,c);
  343. }
  344. #ifndef    oldusputs
  345. /* Buffered puts to a socket */
  346. int
  347. usputs(s,buf)
  348. int s;
  349. unsigned char *buf;
  350. {
  351.     register struct usock *up;
  352.     register struct mbuf *bp;
  353.     unsigned char *cp,*wp;
  354.     int16 len,clen;
  355.     int doflush;
  356.     int eol_len;
  357.     int16 flushpt;
  358.     int ascii;
  359.  
  360.     if((up = itop(s)) == NULLUSOCK){
  361.         errno = EBADF;
  362.         return EOF;
  363.     }
  364. #ifdef    LZW
  365.     if(up->zout != NULLLZW){
  366.         while(*buf != '\0')
  367.             if(usputc(s,*buf++) == EOF)
  368.                 return EOF;
  369.         return 0;
  370.     }
  371. #endif
  372.     ascii = up->flag & SOCK_ASCII;
  373.     if(ascii)
  374.         eol_len = strlen(up->eol);
  375.     doflush = (up->flush != -1) && (strchr(buf,up->flush) != NULLCHAR);
  376.     len = strlen(buf);
  377.  
  378.     while(len != 0){
  379.         if(up->obuf == NULLBUF){
  380.             /* Allocate a buffer of appropriate size */
  381. #ifdef notdef
  382.             /* since I now fragment nr4 packets in send_nr4(),
  383.              * don't worry, be happy :-) - WG7J
  384.              */
  385.             switch(up->type){
  386.             case TYPE_NETROML4:
  387.                 clen = NR4MAXINFO;
  388.                 break;
  389.             default:
  390.                 clen = BUFSIZ;
  391.                 break;
  392.             }
  393. #endif
  394.             clen = BUFSIZ;
  395.             up->obuf = ambufw(clen);
  396.         }
  397.         /* Note: the buffer must be larger than the end-of-line sequence! */
  398.         bp = up->obuf;
  399.         wp = &bp->data[bp->cnt];
  400. #ifdef TNOS_68K
  401.         if(ascii && (cp = strchr(buf,'\l')) != NULLCHAR){
  402. #else
  403.         if(ascii && (cp = strchr(buf,'\n')) != NULLCHAR){
  404. #endif
  405.             /* Copy up to, but not including, newline */
  406.             clen = cp - buf;
  407.         } else {
  408.             /* Copy whole thing */
  409.             clen = len;
  410.         }
  411.         /* ...but no more than the room available */
  412.         clen = min(clen,bp->size - bp->cnt);
  413.         if(clen != 0){
  414.             memcpy(wp,buf,clen);
  415.             wp += clen;
  416.             bp->cnt += clen;
  417.             buf += clen;
  418.             len -= clen;
  419.         }
  420.         /* Set flush threshold to allow for eol, if enabled */
  421.         if(ascii)
  422.             flushpt = bp->size - eol_len;
  423.         else
  424.             flushpt = bp->size;
  425.  
  426.         if(ascii && *buf == '\n' && bp->cnt < flushpt){
  427.             /* Add appropriate end-of-line sequence */
  428.             strncpy(wp,up->eol,eol_len);
  429.             wp += eol_len;
  430.             bp->cnt += eol_len;
  431.             buf++;    /* Skip newline in buffer */
  432.             len--;
  433.         }
  434.         if(bp->cnt >= flushpt){
  435.             /* Buffer full, flush and get another */
  436.             if(usflush(s) == -1)
  437.                 return EOF;
  438.         }
  439.     }    
  440.     if(doflush && usflush(s) == -1)
  441.         return EOF;
  442.  
  443.     return 0;
  444. }
  445.  
  446. #else
  447.  
  448. int
  449. usputs(s,x)
  450. int s;
  451. register unsigned char *x;
  452. {
  453.     while(*x != '\0')
  454.         if(usputc(s,*x++) == EOF)
  455.             return EOF;
  456.     return 0;
  457. }
  458. #endif
  459.  
  460. /* Put a string to standard output socket */
  461. int
  462. tputs(s)
  463. unsigned char *s;
  464. {
  465.     return usputs(Curproc->output,s);
  466. }
  467.  
  468. /* Read a raw character from a socket with stream buffering. */
  469. int
  470. rrecvchar(s)
  471. int s;            /* Socket index */
  472. {
  473.     register struct usock *up;
  474. #ifdef    LZW
  475.     register int c;
  476. #endif
  477.  
  478.     if((up = itop(s)) == NULLUSOCK)
  479.         return EOF;
  480. #ifdef    LZW
  481.     if(up->zin != NULLLZW)
  482.         if((c = lzwdecode(up)) != -1)
  483.             return c;
  484. #endif
  485.     /* Replenish if necessary */
  486.     if(up->ibuf == NULLBUF && recv_mbuf(s,&up->ibuf,0,NULLCHAR,0) <= 0)
  487.         return EOF;
  488.  
  489. #ifdef    LZW
  490.     if(up->zin != NULLLZW)
  491.         if((c = lzwdecode(up)) != -1)
  492.             return c;
  493.         else
  494.             return rrecvchar(s);    /* needs replenish */
  495. #endif
  496.     return PULLCHAR(&up->ibuf);    /* Returns -1 if eof */
  497. }
  498. /* This function recognizes the end-of-line sequence for the stream
  499.  * and translates it into a single '\n'.
  500.  */
  501. int
  502. recvchar(s)
  503. int s;            /* Socket index */
  504. {
  505.     int c;
  506.     register struct usock *up;
  507.  
  508.     if((up = itop(s)) == NULLUSOCK)
  509.         return EOF;
  510.  
  511.     c = rrecvchar(s);
  512.  
  513.     if(c != up->eol[0] || !(up->flag & SOCK_ASCII))
  514.         return c;
  515.  
  516.     /* This is the first char of a eol sequence. If the eol sequence is
  517.      * more than one char long, eat the next character in the input stream.
  518.      */
  519.     if(up->eol[1] != '\0'){
  520.         (void)rrecvchar(s);
  521.     }
  522.     return '\n';
  523. }
  524. /* Flush output on a socket stream */
  525. int
  526. usflush(s)
  527. int s;
  528. {
  529.     register struct usock *up;
  530.     struct mbuf *bp;
  531.  
  532.     if((up = itop(s)) == NULLUSOCK)
  533.         return -1;
  534.  
  535.     if(up->obuf != NULLBUF){
  536. #ifdef    LZW
  537.         if(up->zout != NULLLZW)
  538.             lzwflush(up);
  539. #endif
  540.         bp = up->obuf;
  541.         up->obuf = NULLBUF;
  542.         return send_mbuf(s,bp,0,NULLCHAR,0);
  543.     }
  544.     return 0;
  545. }
  546. /* Flush output socket */
  547. void
  548. tflush()
  549. {
  550.     usflush(Current->output);
  551. }
  552.  
  553. /* Print prompt and read one character */
  554. int
  555. keywait(prompt,flush)
  556. char *prompt;    /* Optional prompt */
  557. int flush;    /* Flush queued input? */
  558. {
  559. int c;
  560. int i;
  561. int echo, edit;
  562.  
  563.     if(flush && socklen(Curproc->input,1) != 0)
  564.         recv_mbuf(Curproc->input,NULLBUFP,0,NULLCHAR,0); /* flush */
  565.     if(prompt == NULLCHAR)
  566.         prompt = "Hit enter to continue"; 
  567.     tprintf(prompt);
  568.     tflush();
  569. #ifdef nope
  570.     echo = Current->ttystate.echo;
  571.     edit = Current->ttystate.edit;
  572.     Current->ttystate.echo = Current->ttystate.edit = 0;
  573. #endif
  574.     c = recvchar(Curproc->input);
  575.     backEmUp (strlen(prompt));
  576. #ifdef nope
  577.     Current->ttystate.echo = echo;
  578.     Current->ttystate.edit = edit; 
  579. #endif
  580.     return (int)c;
  581. }
  582.  
  583. /* Set the end-of-line sequence on a socket */
  584. int
  585. seteol(s,seq)
  586. int s;
  587. char *seq;
  588. {
  589.     register struct usock *up;
  590.  
  591.     if((up = itop(s)) == NULLUSOCK)
  592.         return -1;
  593.  
  594.     if(seq != NULLCHAR)
  595.         strncpy(up->eol,seq,sizeof(up->eol));
  596.     else
  597.         *up->eol = '\0';
  598.     return 0;
  599. }
  600. /* Enable/disable eol translation, return previous state */
  601. int
  602. sockmode(s,mode)
  603. int s,mode;
  604. {
  605.     struct usock *up;
  606.     int prev;
  607.  
  608.     if((up = itop(s)) == NULLUSOCK)
  609.         return -1;
  610.     usflush(s);
  611.     prev = up->flag;
  612.     switch(mode){
  613.     case SOCK_BINARY:
  614.     case SOCK_ASCII:
  615.         up->flag = mode;
  616.         break;
  617.     default:
  618.         break;
  619.     }
  620.     return prev;
  621. }
  622. /* Specify the character to trigger automatic output buffer
  623.  * flushing, or -1 to disable it. Return the previous setting.
  624.  */
  625. int
  626. setflush(s,c)
  627. int s;
  628. int c;
  629. {
  630.     register struct usock *up;
  631.     int old;
  632.  
  633.     if((up = itop(s)) == NULLUSOCK)
  634.         return -1;
  635.  
  636.     old = up->flush;
  637.     up->flush = c;
  638.     return old;
  639. }
  640.  
  641. /* Set the block mode on a socket - WG7J.
  642.  * Primarily used on convers.c to prevent backlog of data and
  643.  * usprintf() calls blocking because of it...
  644.  * returns previous mode
  645.  */
  646. int sockblock(s, value)
  647. int s, value;
  648. {
  649.  
  650.     register struct usock *up;
  651.     int oldval;
  652.  
  653.     if((up = itop(s)) == NULLUSOCK){
  654.         errno = EBADF;
  655.         return -1;
  656.     }
  657.     oldval = up->noblock;
  658.     up->noblock = value;
  659.     return oldval;
  660. }
  661.  
  662.  
  663.